home *** CD-ROM | disk | FTP | other *** search
/ Mac Format 1994 October / Macformat17.cdr / Shareware City / Developers / MungeImage Source / MungeImage.p < prev    next >
Text File  |  1994-06-18  |  14KB  |  549 lines

  1. unit MungeImage;
  2.  
  3. interface
  4.  
  5.     function Main (dctl: DCtlPtr; pb: ParmBlkPtr; sel: integer): OSErr;
  6.  
  7. implementation
  8.  
  9.     uses
  10.         Processes, Aliases;
  11.  
  12.     function FSReadQ (refnum: integer; count: longint; buf: Ptr): OSErr;
  13.     begin
  14.         FSReadQ := FSRead(refnum, count, buf);
  15.     end; (* FSReadQ *)
  16.  
  17.     function MyFSWriteAt (refnum: integer; mode: integer; pos, len: longInt; p: ptr): OSErr;
  18.         var
  19.             pb: ParamBlockRec;
  20.             oe: OSErr;
  21.     begin
  22.         pb.ioRefNum := refnum;
  23.         pb.ioBuffer := p;
  24.         pb.ioReqCount := len;
  25.         pb.ioPosMode := mode;
  26.         pb.ioPosOffset := pos;
  27.         oe := PBWriteSync(@pb);
  28.         if (oe = noErr) & (pb.ioActCount <> len) then begin
  29.             oe := -1;
  30.         end;
  31.         MyFSWriteAt := oe;
  32.     end;
  33.  
  34.     const
  35.         max_drive_count = 15;
  36.         kOptionKey = 58;
  37.         disk_just_inserted = 1;
  38.         disk_read = 2;
  39.  
  40.     type
  41.         diskImageHeader = record
  42.                 name: Str63;
  43.                 data_size: longint;
  44.                 tag_size: longint;
  45.                 data_checksum: longint;
  46.                 tag_checksum: longint;
  47.                 unknown: longint;
  48.             end;
  49.  
  50.     const
  51.         dataCRCheaderOffset = 72;
  52.  
  53.     type
  54.         driveRecord = record
  55.                 flags: signedByte;            (* the following 4 bytes must be in order and immediately in front of dqel *)
  56.                 disk_in_place: signedByte;
  57.                 drive_installed: signedByte;
  58.                 number_of_sides: signedByte;
  59.                 dqel: DrvQEl;
  60.                 image: Ptr;
  61.                 image_size: longint;
  62.                 readonly: boolean;
  63.                 alias: AliasHandle;
  64.                 writeout: boolean;
  65.             end;
  66.  
  67.     (* disk_in_place is 0 iff (image is nil) *)
  68.  
  69.     type
  70.         iconType = array[0..255] of signedByte;
  71.         physIcon = record
  72.                 phys_icon: iconType;
  73.                 location_str: Str63;
  74.             end;
  75.  
  76.     var
  77.         AlreadyOpen: boolean;
  78.         munge_image_psn: ProcessSerialNumber;
  79.         phys_icon: physIcon;
  80.         media_icon: iconType;
  81.         drives: array[1..max_drive_count] of driveRecord;
  82.  
  83.     const
  84.         Size_Of_Globals = sizeof(AlreadyOpen) + sizeof(munge_image_psn) + sizeof(phys_icon) * 2 + sizeof(drives) + $100;
  85.  
  86.     procedure SetRegA4 (n: univ Ptr);
  87.     inline
  88.         $285F;
  89.  
  90.     function CalcChecksum (data: Ptr; datasize: longint): longint;
  91.         type
  92.             bigArray = array[0..123456] of integer;
  93.             bigArrayPtr = ^bigArray;
  94.         var
  95.             i: longint;
  96.             word: integer;
  97.             checksum: longint;
  98.     begin
  99.         if odd(datasize) then begin
  100.             DebugStr('datasize shouldnt be odd!');
  101.         end; (* if *)
  102.         checksum := 0;
  103.         for i := 0 to datasize div 2 - 1 do begin
  104.             word := bigArrayPtr(data)^[i];
  105.             checksum := checksum + band(word, $0000FFFF);
  106.             checksum := brotl(checksum, 31);
  107.         end; (* for *)
  108.         CalcChecksum := checksum;
  109.     end; (* CalcChecksum *)
  110.  
  111.     function DriveExists (drive_num: integer): boolean;
  112.         var
  113.             cur_el: DrvQElPtr;
  114.     begin
  115.         DriveExists := false;
  116.         cur_el := DrvQElPtr(GetDrvQHdr^.qHead);
  117.         while cur_el <> nil do begin
  118.             if cur_el^.dQDrive = drive_num then begin
  119.                 DriveExists := true;
  120.                 leave;
  121.             end; (* if *)
  122.             cur_el := DrvQElPtr(cur_el^.qLink);
  123.         end; (* while *)
  124.     end; (* DriveExists *)
  125.  
  126.     function FindFreeDriveRecord (var ndx: integer): boolean;
  127.         var
  128.             i: integer;
  129.     begin
  130.         ndx := 0;
  131.         for i := 1 to max_drive_count do begin
  132.             if drives[i].disk_in_place = 0 then begin
  133.                 ndx := i;
  134.                 leave;
  135.             end; (* if *)
  136.         end; (* for *)
  137.         FindFreeDriveRecord := (ndx <> 0);
  138.     end; (* FindFreeDriveRecord *)
  139.  
  140.     function DriveToDriveRecord (drive_num: integer; var ndx: integer): OSErr;
  141.         var
  142.             i: integer;
  143.     begin
  144.         ndx := 0;
  145.         for i := 1 to max_drive_count do begin
  146.             if (drives[i].disk_in_place <> 0) and (drives[i].dqel.dQDrive = drive_num) then begin
  147.                 ndx := i;
  148.                 leave;
  149.             end; (* if *)
  150.         end; (* for *)
  151.         if ndx = 0 then begin
  152.             DriveToDriveRecord := nsDrvErr;
  153.         end
  154.         else begin
  155.             DriveToDriveRecord := noErr;
  156.         end; (* if *)
  157.     end; (* DriveToDriveRecord *)
  158.  
  159.     function AnyDriveRecordInUse: boolean;
  160.         var
  161.             i: integer;
  162.     begin
  163.         AnyDriveRecordInUse := false;
  164.         for i := 1 to max_drive_count do begin
  165.             if drives[i].disk_in_place <> 0 then begin
  166.                 AnyDriveRecordInUse := true;
  167.                 leave;
  168.             end; (* if *)
  169.         end; (* for *)
  170.     end; (* AnyDriveRecordInUse *)
  171.  
  172.     function Main (dctl: DCtlPtr; pb: ParmBlkPtr; sel: integer): OSErr;
  173.  
  174.         function DoOpen: OSErr;
  175.             var
  176.                 err: OSErr;
  177.                 i: integer;
  178.                 junk: OSErr;
  179.         begin
  180.             err := noErr;
  181.             if dctl^.dCtlStorage = nil then begin
  182.                 dctl^.dCtlStorage := NewHandleSysClear(Size_Of_Globals);
  183.                 err := MemError;
  184.                 if err = noErr then begin
  185.                     HLock(dctl^.dCtlStorage);
  186.                     SetRegA4(dctl^.dCtlStorage^);
  187.                 end;
  188.             end;
  189.             if (err = noErr) & not AlreadyOpen then begin
  190.                 AlreadyOpen := true;
  191.             end;
  192.             if err = noErr then begin
  193.                 err := GetCurrentProcess(munge_image_psn);
  194.             end; (* if *)
  195.             if (err = noErr) then begin
  196.                 phys_icon.location_str := GetString(128)^^;
  197.                 BlockMove(GetResource('ICN#', 200)^, @phys_icon.phys_icon, sizeof(iconType));
  198.                 BlockMove(GetResource('ICN#', 201)^, @media_icon, sizeof(media_icon));
  199.                 for i := 1 to max_drive_count do begin
  200.                     drives[i].disk_in_place := 0;
  201.                     drives[i].image := nil;
  202.                 end; (* for *)
  203.             end; (* if *)
  204.             DoOpen := err;
  205.         end; (* DoOpen *)
  206.  
  207.         procedure CreateDriveRecord (ndx: integer);
  208.         begin
  209.             drives[ndx].alias := nil;
  210.             drives[ndx].image := nil;
  211.             drives[ndx].disk_in_place := disk_just_inserted;
  212.             drives[ndx].writeout := false;
  213.         end;
  214.  
  215.         procedure DestroydriveRecord (ndx: integer);
  216.         begin
  217.             if drives[ndx].alias <> nil then begin
  218.                 DisposeHandle(handle(drives[ndx].alias));
  219.             end;
  220.             if drives[ndx].image <> nil then begin
  221.                 DisposePtr(drives[ndx].image);
  222.             end;
  223.             drives[ndx].image := nil;
  224.             drives[ndx].disk_in_place := 0;
  225.             drives[ndx].writeout := false;
  226.         end;
  227.  
  228.         function MountImage (fss: FSSpecPtr): OSErr;
  229.             var
  230.                 err: OSErr;
  231.                 junk: OSErr;
  232.                 ndx: integer;
  233.                 header: diskImageHeader;
  234.                 refnum: integer;
  235.                 drive_num: integer;
  236.                 keys: KeyMap;
  237.                 readonly: boolean;
  238.                 oldzone: THz;
  239.         begin
  240.             GetKeys(keys);
  241.             readonly := not keys[kOptionKey];
  242.             err := noErr;
  243.             ndx := 0;        (* important safety tip! *)
  244.             if not FindFreeDriveRecord(ndx) then begin
  245.                 err := -666;
  246.             end
  247.             else begin
  248.                 CreateDriveRecord(ndx);
  249.                 if err = noErr then begin
  250.                     err := FSpOpenDF(fss^, fsRdPerm, refnum);
  251.                 end; (* if *)
  252.                 if err = noErr then begin
  253.                     if not readonly then begin
  254.                         oldzone := GetZone;
  255.                         SetZone(SystemZone);
  256.                         err := NewAlias(nil, fss^, drives[ndx].alias);
  257.                         SetZone(oldzone);
  258.                     end;
  259.                     if err = noErr then begin
  260.                         err := FSReadQ(refnum, sizeof(header), @header);
  261.                     end;
  262.                     if err = noErr then begin
  263.                         drives[ndx].image_size := header.data_size;
  264.                         drives[ndx].image := NewPtrSys(drives[ndx].image_size);
  265.                         err := MemError;
  266.                     end; (* if *)
  267.                     if err = noErr then begin
  268.                         err := FSReadQ(refnum, drives[ndx].image_size, drives[ndx].image);
  269.                     end; (* if *)
  270.                     junk := FSClose(refnum);
  271.                 end; (* if *)
  272.                 if err = noErr then begin
  273.                     drive_num := 4;
  274.                     while DriveExists(drive_num) do begin
  275.                         drive_num := drive_num + 1;
  276.                     end; (* while *)
  277.                     drives[ndx].readonly := readonly;
  278.                     drives[ndx].flags := $80 * ord(readonly);
  279.                     drives[ndx].drive_installed := 0;
  280.                     drives[ndx].number_of_sides := 0;            (* ? should set to 0 for 400K disk images*)
  281.                     drives[ndx].dqel.qType := 1;
  282.                     drives[ndx].dqel.dQDrive := drive_num;
  283.                     drives[ndx].dqel.dQRefNum := pb^.ioCRefNum;
  284.                     drives[ndx].dqel.dQFSID := 0;
  285.                     drives[ndx].dqel.dQDrvSz := drives[ndx].image_size div 512;
  286.                     drives[ndx].dqel.dQDrvSz2 := 0;
  287.                     AddDrive(dctl^.dCtlRefNum, drive_num, @drives[ndx].dqel);
  288.                     junk := PostEvent(diskEvt, drive_num);
  289.                 end
  290.                 else begin
  291.                     DestroyDriveRecord(ndx);
  292.                 end; (* if *)
  293.             end; (* if *)
  294.             MountImage := err;
  295.         end; (* MountImage *)
  296.  
  297.         procedure WriteBack (ndx: integer);
  298.             var
  299.                 err: OSErr;
  300.                 aliascount: integer;
  301.                 fss: array[1..2] of FSSPec;
  302.                 needsUpdate: boolean;
  303.                 rn: integer;
  304.                 crc: longInt;
  305.         begin
  306.             aliascount := 2;
  307.             err := MatchAlias(nil, kARMNoUI + kARMSearch, drives[ndx].alias, aliascount, @fss, needsUpdate, nil, nil);
  308.             if (err = noErr) & (aliascount <> 1) then begin
  309.                 err := -1;
  310.             end;
  311.             if err = noErr then begin
  312.                 err := FSpOpenDF(fss[1], fsRdWrPerm, rn);
  313.                 if err = noErr then begin
  314.                     err := MyFSWriteAt(rn, fsFromStart, SizeOf(diskImageHeader), drives[ndx].image_size, drives[ndx].image);
  315.                     if err = noErr then begin
  316.                         crc := CalcChecksum(drives[ndx].image, drives[ndx].image_size);
  317.                         err := MyFSWriteAt(rn, fsFromStart, dataCRCheaderOffset, SizeOf(crc), @crc);
  318.                     end;
  319.                     err := FSClose(rn);
  320.                 end;
  321.             end;
  322.         end;
  323.  
  324.         function UnMountImage: OSErr;
  325.             var
  326.                 err: OSErr;
  327.                 junk: OSErr;
  328.                 ndx: integer;
  329.         begin
  330.             err := DriveToDriveRecord(pb^.ioVRefNum, ndx);
  331.             if err = noErr then begin
  332.                 if DeQueue(@drives[ndx].dqel, GetDrvQHdr) <> noErr then begin
  333.                     DebugStr('Hmm, removing a non-existant drive');
  334.                 end; (* if *)
  335.                 if not drives[ndx].readonly then begin
  336.                     drives[ndx].writeout := true;
  337.                 end
  338.                 else begin
  339.                     DestroyDriveRecord(ndx);
  340.                 end;
  341.             end; (* if *)
  342.             UnMountImage := err;
  343.         end; (* UnMountImage *)
  344.  
  345.         function DoClose: OSErr;
  346.             var
  347.                 err: OSErr;
  348.         begin
  349.             if AnyDriveRecordInUse then begin
  350.                 err := closErr;
  351.             end
  352.             else begin
  353.                 err := noErr;
  354.             end; (* if *)
  355.             DoClose := err;
  356.         end; (* DoClose *)
  357.  
  358.         function DoPrime: OSErr;
  359.             var
  360.                 err: OSErr;
  361.                 offset: longint;
  362.                 ndx: integer;
  363.         begin
  364.             err := DriveToDriveRecord(pb^.ioVRefNum, ndx);
  365.             if err = noErr then begin
  366.                 offset := dctl^.dCtlPosition;
  367.                 if (offset < 0) or (pb^.ioReqCount < 0) or (offset + pb^.ioReqCount > drives[ndx].image_size) then begin
  368.                     pb^.ioActCount := 0;
  369.                     err := paramErr;
  370.                 end
  371.                 else begin
  372.                     err := noErr;
  373.                     pb^.ioActCount := 0;
  374.                     if odd(pb^.ioTrap) then begin
  375.                         (* write *)
  376.                         if drives[ndx].readonly then begin
  377.                             err := wPrErr;
  378.                         end
  379.                         else begin
  380.                             BlockMove(pb^.ioBuffer, Ptr(ord(drives[ndx].image) + offset), pb^.ioReqCount);
  381.                         end;
  382.                     end
  383.                     else begin
  384.                         (* read *)
  385.                         drives[ndx].disk_in_place := disk_read;
  386.                         BlockMove(Ptr(ord(drives[ndx].image) + offset), pb^.ioBuffer, pb^.ioReqCount);
  387.                     end; (* if *)
  388.                     if err = noErr then begin
  389.                         pb^.ioActCount := pb^.ioReqCount;
  390.                         dctl^.dCtlPosition := dctl^.dCtlPosition + pb^.ioActCount;
  391.                     end;
  392.                 end; (* if *)
  393.             end; (* if *)
  394.             DoPrime := err;
  395.         end; (* DoPrime *)
  396.  
  397.         procedure DoAccRun;
  398.             var
  399.                 i: integer;
  400.         begin
  401.             for i := 1 to max_drive_count do begin
  402.                 if drives[i].disk_in_place <> 0 then begin
  403.                     if drives[i].writeout then begin
  404.                         WriteBack(i);
  405.                         DestroyDriveRecord(i);
  406.                     end;
  407.                 end;
  408.             end;
  409.         end;
  410.  
  411.         function DoControl: OSErr;
  412.             const
  413.                 super_drive_info = $00000404;
  414.             var
  415.                 err: OSErr;
  416.         begin
  417.             case pb^.csCode of
  418.                 1: 
  419.                     err := -1; (* KillIO *)
  420.                 5: 
  421.                     err := noErr; (* Verify Disk *)
  422.                 6: 
  423.                     err := noErr; (* Format Disk *)
  424.                 7: 
  425.                     err := UnMountImage; (* Eject Disk *)
  426.                 8: 
  427.                     if pb^.ioMisc = nil then begin    (* Set Tag Buffer *)
  428.                         err := noErr;
  429.                     end
  430.                     else begin
  431.                         err := -1;
  432.                     end; (* if *)
  433.                 9: 
  434.                     err := -1; (* Track Cache Control *)
  435.                 21:  begin    (* Return Physical Icon *)
  436.                     pb^.ioMisc := @phys_icon;
  437.                     err := noErr;
  438.                 end;
  439.                 22:  begin    (* Return Media Icon *)
  440.                     pb^.ioMisc := @media_icon;
  441.                     err := noErr;
  442.                 end;
  443.                 23:  begin (* Return Drive Info *)
  444.                     pb^.ioMisc := Ptr(super_drive_info);
  445.                     err := noErr;
  446.                 end;
  447.                 accRun: 
  448.                     DoAccRun;
  449.                 666:  begin
  450.                     err := MountImage(FSSpecPtr(pb^.ioMisc));
  451.                 end;
  452.                 667: 
  453.                     err := noErr;
  454.                 18244:  begin
  455.                     err := -1;
  456.                 end;
  457.                 otherwise
  458.                     err := controlErr;
  459.             end; (* case *)
  460.             DoControl := err;
  461.         end; (* DoControl *)
  462.  
  463.         function DoStatus: OSErr;
  464.             const
  465.                 mfm_1440_capacity = 1440 * 2;
  466.                 mfm_1440_stuff = $D2120050;
  467.             type
  468.                 formatDesc = record
  469.                         capacity: longint;
  470.                         stuff: longint;
  471.                     end;
  472.                 formatParams = record
  473.                         count: integer;
  474.                         point: ^formatDesc;
  475.                     end;
  476.                 formatParamsPtr = ^formatParams;
  477.                 statusParams = record
  478.                         current_track: integer;
  479.                         flags: signedByte;            (* the following 4 bytes must be in order and immediately in front of dqel *)
  480.                         disk_in_place: signedByte;
  481.                         drive_installed: signedByte;
  482.                         number_of_sides: signedByte;
  483.                         dqel: DrvQEl;
  484.                     end;
  485.                 statusParamsPtr = ^statusParams;
  486.             var
  487.                 err: OSErr;
  488.                 ndx: integer;
  489.         begin
  490.             case pb^.csCode of
  491.                 6:  begin (* Return Format List *)
  492.                     err := DriveToDriveRecord(pb^.ioVRefNum, ndx);
  493.                     if err = noErr then begin
  494.                         with formatParamsPtr(@pb^.csParam)^ do begin
  495.                             if count > 0 then begin
  496.                                 count := 1;
  497.                                 point^.capacity := drives[ndx].image_size div 512;
  498.                                 point^.stuff := 0;
  499.                                 err := noErr;
  500.                             end
  501.                             else begin
  502.                                 err := paramErr;
  503.                             end; (* if *)
  504.                         end; (* with *)
  505.                     end; (* if *)
  506.                 end;
  507.                 8:  begin
  508.                     err := DriveToDriveRecord(pb^.ioVRefNum, ndx);
  509.                     if err = noErr then begin
  510.                         with statusParamsPtr(@pb^.csParam)^ do begin
  511.                             current_track := 0;
  512.                             flags := drives[ndx].flags;
  513.                             disk_in_place := drives[ndx].disk_in_place;
  514.                             drive_installed := drives[ndx].drive_installed;
  515.                             number_of_sides := drives[ndx].number_of_sides;
  516.                             dqel := drives[ndx].dqel;
  517.                             dqel.dQDrvSz := -1;
  518.                             dqel.dQDrvSz2 := 0;
  519.                         end; (* with *)
  520.                         err := noErr;
  521.                     end; (* if *)
  522.                 end;
  523.                 otherwise
  524.                     err := controlErr;
  525.             end; (* case *)
  526.             DoStatus := err;
  527.         end; (* DoStatus *)
  528.  
  529.         var
  530.             err: OSErr;
  531.     begin
  532.         case sel of
  533.             0: 
  534.                 err := DoOpen;
  535.             1: 
  536.                 err := DoPrime;
  537.             2: 
  538.                 err := DoControl;
  539.             3: 
  540.                 err := DoStatus;
  541.             4: 
  542.                 err := DoClose;
  543.             otherwise
  544.                 err := noErr;
  545.         end; (* case *)
  546.         Main := err;
  547.     end; (* Main *)
  548.  
  549. end. (* MungeImage *)